package com.ggb.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Set;

public class NioTest12 {
    public static void main(String[] args) throws IOException {
        int[] ports = new int[5];

        for (int i = 0; i < ports.length; i++) {
            ports[i] = 5000 + i;
        }
        Selector selector = Selector.open();

        for (int i = 0; i < ports.length; i++) {
            // 阻塞非阻塞是对通道来说的
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            // 套接字是从通道获取的 但是这个时候通道都还没有真正的accept的连接 只是为了注册
            ServerSocket socket = serverSocketChannel.socket();
            // 绑定端口是用的套接字 不是用的通道
            InetSocketAddress inetSocketAddress = new InetSocketAddress(ports[i]);
            socket.bind(inetSocketAddress);
            // 在通道中注册selector 而不是给socket注册
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("监听端口： " + ports[i]);
        }

        while (true) {
            int number = selector.select();
//            System.out.println("number: " + number);
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey next = iterator.next();
                if (next.isAcceptable()) {
                    // 坑1 这里要强制类型转换
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) next.channel();
                    // 坑2 这里如果没有accpt的话 这个套接字在下一次依然能被select
                    SocketChannel channel = serverSocketChannel.accept();
                    channel.configureBlocking(false);
                    // 坑3 是把accept状态的套接字变为可读 不是继续变为可接受 不然是死循环
                    channel.register(selector, SelectionKey.OP_READ);
                    // 为什么这里remove之后还这么多连接？ 并没有卵用 调用select之后 selectKeySet会更新
                    iterator.remove();
                    System.out.println("size: "+selectionKeys.size());
                    System.out.println("获取客户端连接: " + channel);
                }
            }
        }
    }
}
